package com.tsd.common.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaSchemeService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.scheme.WxMaGenerateSchemeRequest;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.net.url.UrlPath;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tsd.common.dao.CommonShortUrlMapper;
import com.tsd.common.entity.CommonShortUrl;
import com.tsd.common.entity.CommonShortUrlExt;
import com.tsd.common.service.CommonShortUrlService;
import com.tsd.core.datasource.DataSourceContextHolder;
import com.tsd.core.datasource.DataSourceInitService;
import com.tsd.core.datasource.SpringContextUtil;
import com.tsd.core.thread.ThreadPoolTaskUtil;
import com.tsd.core.utils.DoubleUtil;
import com.tsd.core.utils.ExceptionUtil;
import com.tsd.core.utils.HlpUtils;
import com.tsd.core.utils.ShortUrlUtil;
import com.tsd.core.vo.PageBean;
import com.tsd.service.BaseServiceImpl;
import com.tsd.system.entity.SysUser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 描述：CommonShortUrl 服务实现层
 *
 * @author Hillpool
 * @date 2022/12/07 11:35:18
 */
@Service
public class CommonShortUrlServiceImpl extends BaseServiceImpl implements CommonShortUrlService {

    public static final Logger LOGGER = LoggerFactory.getLogger(CommonShortUrlServiceImpl.class);

    @Resource
    private CommonShortUrlMapper commonShortUrlMapper;
    @Resource
    private WxMaService wxMaService;

    @Override
    public CommonShortUrl getCommonShortUrlById(Long id) throws Exception {
        return commonShortUrlMapper.selectByPrimaryKey(id);
    }

    @Override
    public CommonShortUrlExt queryBySid(String sid) throws Exception {
        return commonShortUrlMapper.selectBySid(sid);
    }

    @Override
    public void deleteCommonShortUrls(List<String> list, SysUser opUser) throws Exception {
        for (String sid : list) {
            CommonShortUrl old = commonShortUrlMapper.selectBySid(sid);
            super.checkEmpty(old, "该记录不存在");
            super.autoInjectBaseData(old, opUser, TYPE_DELETE);
            commonShortUrlMapper.updateByPrimaryKeySelective(old);
        }
    }

    @Override
    public void saveCommonShortUrl(CommonShortUrlExt record, SysUser opUser) throws Exception {
        if (HlpUtils.isEmpty(record.getId())) {
            super.autoInjectBaseData(record, opUser, this.TYPE_CREATE);
            commonShortUrlMapper.insertSelective(record);
        } else {
            super.autoInjectBaseData(record, opUser, this.TYPE_UPDATE);
            commonShortUrlMapper.updateByPrimaryKeySelective(record);
        }
    }

    @Override
    public List<CommonShortUrlExt> findCommonShortUrls(Map<String, Object> params, PageBean page) throws Exception {
        return commonShortUrlMapper.selectByPage(params, page);
    }

    @Override
    public List<CommonShortUrlExt> findCommonShortUrls(Map<String, Object> params) throws Exception {
        return commonShortUrlMapper.selectByParams(params);
    }

    @Override
    public List<CommonShortUrlExt> queryByOwnerList(String bizType, List<String> ownerList) {
        return ThreadPoolTaskUtil.queryInList4Split(ownerList, itemList -> {
            CommonShortUrlExt params = new CommonShortUrlExt();
            params.setDr(0);
            params.setBiz_type(bizType);
            params.setOwner_list(itemList);
            return commonShortUrlMapper.selectByEntity(params);
        });
    }

    @Override
    public CommonShortUrlExt queryValidByCode(String code) {
        CommonShortUrlExt urlExt = commonShortUrlMapper.selectValidByCode(code);
        if (urlExt != null) {
            Date now = new Date();
            if (CommonShortUrlExt.LONG_URL_TYPE_DIRECT_WX_MINI.equals(urlExt.getLong_url_type())) {
                double checkExpire = DoubleUtil.sub(urlExt.getExpire_time().getTime(), now.getTime());
                if (checkExpire >= 0) {
                    return urlExt;
                }
                if (CommonShortUrlExt.BIZ_TYPE_DTS_GOODS.equals(urlExt.getBiz_type())) {
                    Date expireTime = HlpUtils.getNextDate(now, 30);
                    String openlink = this.genDirectWxMiniUrl(null, 30, urlExt);
                    if (!HlpUtils.isEmpty(openlink)) {
                        urlExt.setExpire_time(expireTime);
                        urlExt.setLong_url(openlink);
                        urlExt.setNeed_upate(true);
                    }
                }
            }
        }
        return urlExt;
    }

    @Override
    public String genDirectWxMiniUrl(String jumpWxaPath, String jumpWxaQuery, Date expireTime, WxMaConfig config) {
        wxMaService.setWxMaConfig(config);
        try {
            WxMaGenerateSchemeRequest.JumpWxa jumpWxa = WxMaGenerateSchemeRequest.JumpWxa.newBuilder()
                    .path(jumpWxaPath).query(jumpWxaQuery).build();
            //.envVersion("trial")
            WxMaSchemeService wxMaSchemeService = wxMaService.getWxMaSchemeService();
            WxMaGenerateSchemeRequest schemeRequest = WxMaGenerateSchemeRequest.newBuilder()
                    .jumpWxa(jumpWxa).expireTime(expireTime.getTime()).build();
            return wxMaSchemeService.generate(schemeRequest);
        } catch (Exception e) {
            LOGGER.error(ExceptionUtil.getStackTraceFromException(e));
        }
        return null;
    }

    @Override
    public String genDirectWxMiniUrl(Map<String, Object> map, int days, CommonShortUrlExt urlExt) {
        Date now = new Date();
        List<String> strList = new ArrayList<>();
        strList.add("id=" + urlExt.getOwner_sid());
        if (map != null && !map.isEmpty()) {
            for (String key : map.keySet()) {
                String s = HlpUtils.getString(map, key);
                try {
                    s = URLEncoder.encode(s, "UTF-8");
                    strList.add(key + "=" + s);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        String longUrl = urlExt.getLong_url();
        if (CommonShortUrlExt.BIZ_TYPE_DTS_GOODS.equals(urlExt.getBiz_type())) {
            String jumpWxaPath = "/pages/goods/goods";
            String jumpWxaQuery = StringUtils.join(strList, "&");
            Date expireTime = HlpUtils.getNextDate(now, days);
            JSONObject object = JSON.parseObject(urlExt.getWx_config());
            WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
            config.setAppid(object.getString("app_id"));
            config.setSecret(object.getString("app_secret"));
            String openlink = this.genDirectWxMiniUrl(jumpWxaPath, jumpWxaQuery, expireTime, config);
            if (!HlpUtils.isEmpty(openlink)) {
                longUrl = openlink;
            }
        }
        return longUrl;
    }

    @Override
    public void genDirectWxMiniUrl(String jumpWxaPath, String jumpWxaQuery, String ownerSid, String bizType, WxMaConfig config, HttpServletRequest request) {
        if (HlpUtils.isEmpty(ownerSid)) {
            return;
        }
        try {
            String dataSource = DataSourceContextHolder.getDataSourceType();
            Entity entity = DataSourceInitService.getAccountSet(dataSource);
            String unionKey = dataSource + "@" + bizType + "@" + CommonShortUrlExt.LONG_URL_TYPE_DIRECT_WX_MINI + "@" + ownerSid;
            String shortUrl = ShortUrlUtil.generate(unionKey);

            Date now = new Date();
            CommonShortUrlExt urlExt = commonShortUrlMapper.selectValidByCode(shortUrl);
            if (urlExt != null) {
                double checkExpire = DoubleUtil.sub(urlExt.getExpire_time().getTime(), now.getTime());
                if (checkExpire >= 0) {
                    return;
                }
            } else {
                urlExt = new CommonShortUrlExt();
                urlExt.setBiz_type(bizType);
                urlExt.setOwner_sid(ownerSid);
                urlExt.setLong_url_type(CommonShortUrlExt.LONG_URL_TYPE_DIRECT_WX_MINI);
                urlExt.setCode(shortUrl);
                Environment environment = SpringContextUtil.getBean(Environment.class);
                String contextPath = environment.getProperty("server.servlet.context-path");
                UrlBuilder builder = UrlBuilder.ofHttp(request.getRequestURL().toString(), CharsetUtil.CHARSET_UTF_8);
                builder.setPath(UrlPath.of(contextPath, CharsetUtil.CHARSET_UTF_8));
                builder.addPath("/s").addPath(StrUtil.SLASH + entity.getLong("id")).addPath(StrUtil.SLASH + shortUrl);
                //微信短链所要求服务器必须是https
                String url = builder.build();
                url = url.replace("http://", "https://");
                urlExt.setShort_url(url);
            }
            JSONObject object = new JSONObject();
            object.put("app_id", config.getAppid());
            object.put("app_secret", config.getSecret());
            urlExt.setWx_config(object.toJSONString());
            wxMaService.setWxMaConfig(config);
            Date expireTime = HlpUtils.getNextDate(now, 30);
            urlExt.setExpire_time(expireTime);
            String openlink = this.genDirectWxMiniUrl(jumpWxaPath, jumpWxaQuery, expireTime, config);
            if (HlpUtils.isEmpty(openlink)) {
                return;
            }
            urlExt.setLong_url(openlink);
            this.saveCommonShortUrl(urlExt, null);
        } catch (Exception e) {
            LOGGER.error(ExceptionUtil.getStackTraceFromException(e));
        }
    }
}
